
package com.shiku.imserver.common.tcp;


import com.shiku.imserver.common.packets.ImPacket;

import java.nio.ByteBuffer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tio.core.ChannelContext;
import org.tio.core.exception.AioDecodeException;
import org.tio.core.intf.Packet;


public class TcpServerDecoder {
    private static Logger logger = LoggerFactory.getLogger(TcpServerDecoder.class);


    public static TcpPacket decode(ByteBuffer buffer, ChannelContext channelContext) throws AioDecodeException {

        if (!isHeaderLength(buffer)) {

            return null;

        }


        byte version = buffer.get();


        byte maskByte = buffer.get();

        Integer synSeq = Integer.valueOf(0);


        if (ImPacket.decodeHasSynSeq(maskByte)) {

            synSeq = Integer.valueOf(buffer.getInt());

        }


        short cmdByte = buffer.getShort();


        int bodyLen = buffer.getInt();


        if (bodyLen < 0) {

            throw new AioDecodeException("bodyLength [" + bodyLen + "] is not right, remote:" + channelContext.getClientNode());

        }

        int readableLength = buffer.limit() - buffer.position();

        int validateBodyLen = readableLength - bodyLen;


        if (validateBodyLen < 0) {

            return null;

        }

        byte[] body = new byte[bodyLen];

        try {

            buffer.get(body, 0, bodyLen);

        } catch (Exception e) {

            logger.error(e.toString());

        }


        TcpPacket tcpPacket = new TcpPacket(cmdByte, body);

        tcpPacket.setVersion(version);

        tcpPacket.setMask(maskByte);


        if (synSeq.intValue() > 0) {

            tcpPacket.setSynSeq(synSeq);

            try {

                channelContext.getGroupContext().getAioHandler().handler((Packet) tcpPacket, channelContext);

            } catch (Exception e) {

                logger.error("同步发送解码调用handler异常!" + e);

            }

        }

        return tcpPacket;

    }


    private static boolean isHeaderLength(ByteBuffer buffer) throws AioDecodeException {

        int readableLength = buffer.limit() - buffer.position();

        if (readableLength == 0) {

            return false;

        }


        int index = buffer.position();


        try {

            buffer.get(index);

            index++;


            byte maskByte = buffer.get(index);

            index++;


            if (ImPacket.decodeHasSynSeq(maskByte)) {

                buffer.getInt(index);

                index += 4;

            }


            buffer.getShort(index);

            index += 2;


            buffer.getInt(index);

            index += 4;

            return true;

        } catch (Exception e) {

            return false;

        }

    }

}


